package com.ctshk.rpc.order.hotel.service.impl;
import cn.hutool.core.util.RandomUtil;
import com.ctshk.common.enums.hotel.HotelApiSupplier;
import com.ctshk.rpc.hotel.dto.BookingCheckDTO;
import com.ctshk.rpc.hotel.req.NCNBHotelCreateOrderReq;
import com.ctshk.rpc.hotel.service.INCNBHotelService;
import com.ctshk.rpc.payment.enums.PayCurrency;
import com.google.common.collect.Lists;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.constant.RedisConstants;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.*;
import com.ctshk.common.enums.hotel.TouristType;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.model.TokenUser;
import com.ctshk.common.utils.DateUtil;
import com.ctshk.common.utils.EntityUtil;
import com.ctshk.common.utils.SnowflakeIdWorker;
import com.ctshk.rpc.booking.enums.SupplierReserveTypeEnum;
import com.ctshk.rpc.booking.req.system.hotel.add.SupplierOrderSystemHotelAddReq;
import com.ctshk.rpc.booking.req.system.hotel.add.SupplierSystemOrderHotelCheckInAddReq;
import com.ctshk.rpc.booking.req.system.hotel.add.SupplierSystemOrderHotelTouristAddReq;
import com.ctshk.rpc.booking.service.ISupplierOrderService;
import com.ctshk.rpc.finance.req.bill.BillAddCollectionReq;
import com.ctshk.rpc.finance.service.IFinanceBillService;
import com.ctshk.rpc.hotel.dto.HotelListDTO;
import com.ctshk.rpc.hotel.dto.HotelProductInfoDTO;
import com.ctshk.rpc.hotel.req.HotelOrderRoomCustomerInfo;
import com.ctshk.rpc.hotel.service.IHotelProductService;
import com.ctshk.rpc.hotel.service.IHotelService;
import com.ctshk.rpc.iotc.dto.OperateBankPreferenceQueryDTO;
import com.ctshk.rpc.iotc.req.OperateBankConformQueryReq;
import com.ctshk.rpc.iotc.req.OperateBankDeductReq;
import com.ctshk.rpc.iotc.service.IOperateBankPreferenceService;
import com.ctshk.rpc.order.hotel.dto.HotelOrderSubmitDTO;
import com.ctshk.rpc.order.hotel.entity.*;
import com.ctshk.rpc.order.hotel.mapper.*;
import com.ctshk.rpc.order.hotel.req.HotelOrderCollectionReq;
import com.ctshk.rpc.order.hotel.req.HotelOrderSubmitReq;
import com.ctshk.rpc.order.hotel.service.IHotelOrderBookingService;
import com.ctshk.rpc.starvip.req.TransactionIntegralReq;
import com.ctshk.rpc.starvip.service.IStarVipBusinessService;
import com.ctshk.rpc.system.constants.Constants;
import com.ctshk.rpc.system.dto.MainDataCurrencyListDTO;
import com.ctshk.rpc.system.dto.MainDataCurrencyQueryDTO;
import com.ctshk.rpc.system.dto.SysDepartmentDTO;
import com.ctshk.rpc.system.dto.UserDTO;
import com.ctshk.rpc.system.enums.CrmMemberProductPointsRateEnum;
import com.ctshk.rpc.system.req.MainDataCurrencyListReq;
import com.ctshk.rpc.system.req.MainDataCurrencyUpdateStatusReq;
import com.ctshk.rpc.system.req.crm.member.CrmMemberQueryReq;
import com.ctshk.rpc.system.req.crm.member.CrmMemberUpdatePointsReq;
import com.ctshk.rpc.system.service.IMainDataCurrencyService;
import com.ctshk.rpc.system.service.ISysDepartmentService;
import com.ctshk.rpc.system.service.ISysUserService;
import com.github.houbb.heaven.util.util.CollectionUtil;
import com.github.kfcfans.powerjob.client.OhMyClient;
import com.github.kfcfans.powerjob.common.response.ResultDTO;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 酒店订单表 服务实现类
 * </p>
 *
 * @author yinhuan
 * @since 2021-03-08
 */
@Slf4j
@RefreshScope
@DubboService
public class HotelOrderBokingServiceImpl implements IHotelOrderBookingService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private HotelOrderMapper hotelOrderMapper;
    @Autowired
    private HotelOrderTouristMapper hotelOrderTouristMapper;
    @DubboReference
    private IMainDataCurrencyService iMainDataCurrencyService;
    @Autowired
    private HotelOrderCollectionMapper hotelOrderCollectionMapper;
    @Autowired
    private HotelManualOrderMapper hotelManualOrderMapper;
    @Autowired
    private HotelOrderRefundMapper hotelOrderRefundMapper;
    @Autowired
    private HotelOrderReceiptMapper hotelOrderReceiptMapper;

    @DubboReference
    private INCNBHotelService ncnbHotelService;
    @DubboReference
    private IHotelService hotelService;
    @DubboReference
    private IHotelProductService hotelProductService;
    @DubboReference
    private IMainDataCurrencyService mainDataCurrencyService;
    @DubboReference
    private ISysUserService sysUserService;
    @DubboReference
    private ISysDepartmentService sysDepartmentService;
    @DubboReference
    private IStarVipBusinessService starVipBusinessService;
    @DubboReference
    private IOperateBankPreferenceService operateBankPreferenceService;
    @DubboReference
    private ISupplierOrderService supplierOrderService;
    @DubboReference
    private IFinanceBillService financeBillService;

    @Value("${schedule.config.domain}")
    private String domain;

    @Value("${schedule.config.app-name}")
    private String appName;

    @Value("${schedule.config.password}")
    private String password;

    @Value("${schedule.job-id.order.hotel}")
    private long jobId;

    /**
     * 生成查询号码，六位随机数字字符串
     *
     * @return
     */
    private String generatorInquiryNumber() {
        String randomNumber = String.valueOf((int) ((Math.random() * 9 + 1) * 100000));
        return randomNumber;
    }

    /**
     * 生成订单号
     * H+年後2位+年月日6位+3位隨機數字
     * @param userId
     * @return
     */
    private String generatorOrderNumber(Long userId) {
        UserDTO userDTO = sysUserService.loadUserByParam(userId, 1);
        String employeeNumber = userDTO.getEmployeeNumber();
        SysDepartmentDTO sysDepartmentDTO = sysDepartmentService.queryOne(userDTO.getDeptId());
        String deptCode = sysDepartmentDTO.getDeptCode();
        String dateCode = DateUtil.fmtNum(LocalDate.now());
        String randomNumber = String.valueOf((int) ((Math.random() * 9 + 1) * 100));
        StringBuilder orderNumberSb = new StringBuilder();
        orderNumberSb.append("H").append(deptCode).append(employeeNumber).append(dateCode).append(randomNumber);
        return orderNumberSb.toString();
    }

    /**
     * 生成收款单号:
     * SKD+年後2位+月日4位+時分秒6位+2位隨機數字
     */
    private String generatorPaymentNumber(LocalDateTime nowLocalDateTime) {
        String yearCode = String.valueOf(nowLocalDateTime.getYear()).substring(2, 4);
        String dateCode = DateUtil.fmtMd(LocalDate.now());
        String hourCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getHour()), 2, "0");
        String minuteCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getMinute()), 2, "0");
        String secondCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getSecond()), 2, "0");
        String randomNumber = String.valueOf((int) ((Math.random() * 9 + 1) * 10));
        StringBuilder orderNumberSb = new StringBuilder();
        orderNumberSb.append("SKD").append(yearCode).append(dateCode).append(hourCode)
                .append(minuteCode).append(secondCode).append(randomNumber);
        return orderNumberSb.toString().toUpperCase();
    }

    /**
     * 生成收據號碼：門市編號+員工編號+年後2位+月日4位+B+時分秒6位+（S），
     * 例如：XS-C07884-200407-B-110008（S）
     *
     * @param userDTO
     * @return
     */
    private String generatorReceiptNumber(UserDTO userDTO, SysDepartmentDTO sysDepartmentDTO, LocalDateTime
            nowLocalDateTime) {
        String symbol = "-";
        String employeeNumber = userDTO.getEmployeeNumber();
        String deptCode = sysDepartmentDTO.getDeptCode();
        String dateCode = DateUtil.fmtNum(LocalDate.now());
        String hourCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getHour()), 2, "0");
        String minuteCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getMinute()), 2, "0");
        String secondCode = StringUtils.leftPad(String.valueOf(nowLocalDateTime.getSecond()), 2, "0");
        StringBuilder receiptNumberSb = new StringBuilder();
        receiptNumberSb.append("XS").append(symbol).append(deptCode).append(symbol)
                .append(employeeNumber).append(symbol)
                .append(dateCode).append(symbol).append("-B-")
                .append(hourCode).append(symbol)
                .append(minuteCode).append(symbol)
                .append(secondCode).append(symbol)
                .append("（S）");
        return receiptNumberSb.toString().toUpperCase();
    }

    /**
     * 根据币种ID获取汇率，获取汇率,
     *
     * @return
     */
    private MainDataCurrencyQueryDTO getExchangeRateByName(Long currencyId) {
        MainDataCurrencyUpdateStatusReq mainDataCurrencyUpdateStatusReq = new MainDataCurrencyUpdateStatusReq();
        mainDataCurrencyUpdateStatusReq.setId(currencyId);
        Result<MainDataCurrencyQueryDTO> queryCurrencyRateResult = mainDataCurrencyService.query(mainDataCurrencyUpdateStatusReq);
        log.info("【查询汇率】exchange rate:{}", JSON.toJSONString(queryCurrencyRateResult));
        if (!queryCurrencyRateResult.isSuccess()) {
            SystemError defined = SystemError.getDefined(queryCurrencyRateResult.getCode());
            throw new BusinessException(defined);
        }
        return queryCurrencyRateResult.getData();
    }
    /**
     * 根据币种名称获取汇率
     *
     * @param currencySy
     * @return
     */
    private MainDataCurrencyListDTO getExchangeRateByName(String currencySy) {
        MainDataCurrencyListReq mainDataCurrencyListReq = new MainDataCurrencyListReq();
        mainDataCurrencyListReq.setName(currencySy);
        PageResponse<MainDataCurrencyListDTO> list = mainDataCurrencyService.list(mainDataCurrencyListReq);
        if (com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(list.getRecords())) {
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60003);
        }
        return list.getRecords().get(0);
    }

    /**
     * 根据总价计算应收金额，减去会员积分和优惠券
     * @param req
     * @return
     */
    private BigDecimal buildReceivableAmount(HotelOrderSubmitReq req) {

        // 计算总价=(房间单价+服务费)*房间数*住宿晚数
        BigDecimal receivableAmount = req.getUnitPrice().add(req.getTaxation()).multiply(new BigDecimal(req.getRoomNumber())).multiply(new BigDecimal(req.getNights()));
        //计算应收价格-是否使用积分
        if (req.getUsingPoints() != null && req.getUsingPoints() != 0) {
            if (req.getUsingPoints() < 0) {
                // 抵扣积分必须大于0;
                throw new BusinessException(SystemError.HOTEL_10074);
            }
            BigDecimal usingPoints = new BigDecimal(String.valueOf(req.getUsingPoints()));

            //计算应收价格-计算积分
            BigDecimal usingPointsCNY = usingPoints.divide(Constants.POINTS_TO_CNY, 2, BigDecimal.ROUND_HALF_UP);
            //人民币兑港币
            MainDataCurrencyListDTO exchangeRateByName = getExchangeRateByName(Currency.CNY.getSymbol());
            BigDecimal crmExchangeRate = exchangeRateByName.getCrmExchangeRate();
            BigDecimal usingPointsHKD = usingPointsCNY.multiply(crmExchangeRate);
            receivableAmount = receivableAmount.subtract(usingPointsHKD);
        }
        //计算应收价格-计算推广码（优惠券）
        if (req.getCouponCode() != null) {
            receivableAmount = receivableAmount.subtract(req.getCouponDeduction());
        }
        if (receivableAmount.compareTo(BigDecimal.ZERO) == -1) {
            // 总价减去积分价后为负数，不予许提交
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60007);
        }
        return receivableAmount;
    }

    @Override
    @GlobalTransactional
    //@Transactional
    public HotelOrderSubmitDTO submit(HotelOrderSubmitReq req, TokenUser currentUser) {
        if (req.getHotelOrderRoomCustomerInfos().size() != req.getRoomNumber()) {
            throw new BusinessException(SystemError.HOTEL_10081);
        }
        HotelListDTO hotelDTO = hotelService.queryDetail(req.getHotelId());
        if (hotelDTO == null) {
            throw new BusinessException(SystemError.HOTEL_10010);
        }
        HotelProductInfoDTO hotelProductDTO = hotelProductService.selectInfo(req.getHotelProductId());
        if (hotelProductDTO == null) {
            throw new BusinessException(SystemError.HOTEL_10014);
        }
        LocalDateTime now = LocalDateTime.now();
        HotelOrder hotelOrder = new HotelOrder();
        Long orderId = SnowflakeIdWorker.nextId();
        String orderNumber = generatorOrderNumber(currentUser.getId());
        hotelOrder.setId(orderId);
        hotelOrder.setOrderNumber(orderNumber);
        hotelOrder.setInquiryNumber(RandomUtil.randomNumbers(6));
        hotelOrder.setOrdersType(req.getOrdersType());
        hotelOrder.setHotelId(hotelProductDTO.getHotelId());
        hotelOrder.setRoomId(hotelProductDTO.getRoomId());
        hotelOrder.setHotelProductId(req.getHotelProductId());
        hotelOrder.setCostCurrencyId(req.getCostCurrencyId());
        hotelOrder.setCostCurrencyName(req.getCostCurrencyName());
        hotelOrder.setCostExchangeRate(req.getCostExchangeRate());
        hotelOrder.setCheckInDate(req.getCheckInDate());
        hotelOrder.setCheckOutDate(req.getCheckOutDate());
        hotelOrder.setNumber(req.getRoomNumber());
        hotelOrder.setIsAgent(req.getAgencyId() != null ? 1 : 0);
        hotelOrder.setAgencyId(req.getAgencyId());
        hotelOrder.setAgencyCompany(req.getAgencyCompany());
        hotelOrder.setPaymentStatus(OrderPaymentStatus.UN_PAYMENT.getCode());
        hotelOrder.setScheduledStatus(null);
        hotelOrder.setCancelStatus(null);
        hotelOrder.setSalesmanId(currentUser.getId());
        hotelOrder.setSalesmanName(currentUser.getNickname());
        hotelOrder.setSurname(req.getHotelOrderContactPersonInfo().getContactSurname());
        hotelOrder.setName(req.getHotelOrderContactPersonInfo().getContactName());
        hotelOrder.setContactName(StrUtil.concat(true, req.getHotelOrderContactPersonInfo().getContactSurname(), req.getHotelOrderContactPersonInfo().getContactName()));
        hotelOrder.setContactMobile(req.getHotelOrderContactPersonInfo().getContactMobile());
        hotelOrder.setContactMobileAreaCodeId(req.getHotelOrderContactPersonInfo().getContactMobileAreaCodeId());
        hotelOrder.setContactMobileAreaCode(req.getHotelOrderContactPersonInfo().getContactMobileAreaCode());
        hotelOrder.setContactCountryId(req.getHotelOrderContactPersonInfo().getContactCountryId());
        hotelOrder.setContactCountryName(req.getHotelOrderContactPersonInfo().getContactCountryName());
        hotelOrder.setContactAppellation(req.getHotelOrderContactPersonInfo().getContactAppellation());
        hotelOrder.setContactEmail(req.getHotelOrderContactPersonInfo().getContactEmail());
        hotelOrder.setNights(req.getNights());
        hotelOrder.setPayExpireDate(now.plusMinutes(30));
        hotelOrder.setMemberId(req.getMemberId());
        hotelOrder.setUsingPoints(req.getUsingPoints());
        hotelOrder.setRemark(req.getRemark());
        hotelOrder.setCreateId(currentUser.getId());
        hotelOrder.setIsDeleted(0);
        hotelOrder.setUnitPrice(req.getUnitPrice());
        hotelOrder.setOrderAmount(buildReceivableAmount(req));
        hotelOrder.setReceivableAmount(buildReceivableAmount(req));
        hotelOrder.setReceiptAmount(new BigDecimal(0));
        hotelOrder.setRefundedAmount(new BigDecimal(0));
        hotelOrder.setSalesMethods(req.getSalesMethods());
        hotelOrder.setCityName(hotelDTO.getCityName());
        hotelOrder.setBrandName(hotelDTO.getBrandName());
        hotelOrder.setHotelName(hotelDTO.getName());
        hotelOrder.setRoomName(req.getRoomName());
        hotelOrder.setHotelProductName(hotelDTO.getName());
        hotelOrder.setHasBreakfast(hotelProductDTO.getHasBreakfast());
        hotelOrder.setCouponCode(req.getCouponCode());
        hotelOrder.setCouponDeduction(req.getCouponDeduction());
        hotelOrder.setSource(OrderSource.CPM.getCode());
        hotelOrder.setGmtCreate(now);
        hotelOrder.setGmtModified(now);

        hotelOrderMapper.insert(hotelOrder);

        //保存旅客信息
        if(CollectionUtil.isNotEmpty(req.getHotelOrderRoomCustomerInfos())){
            for (int i = 0; i < req.getHotelOrderRoomCustomerInfos().size(); i++) {
                HotelOrderRoomCustomerInfo hotelOrderRoomCustomerInfo = req.getHotelOrderRoomCustomerInfos().get(i);
                HotelOrderTourist hotelOrderTourist = new HotelOrderTourist();
                hotelOrderTourist.setId(IdWorker.getId());
                hotelOrderTourist.setGmtModified(now);
                hotelOrderTourist.setCreateId(currentUser.getId());
                hotelOrderTourist.setGender(null);
                hotelOrderTourist.setIsDeleted(0);
                hotelOrderTourist.setModifiedId(currentUser.getId());
                hotelOrderTourist.setName(hotelOrderRoomCustomerInfo.getName());
                hotelOrderTourist.setOrderId(orderId);
                hotelOrderTourist.setSurname(hotelOrderRoomCustomerInfo.getSurName());
                hotelOrderTourist.setTouristName(hotelOrderRoomCustomerInfo.getSurName()+hotelOrderRoomCustomerInfo.getName());
                // 1:成人，2：小童  自录入的时候不区分，API可能需要
                hotelOrderTourist.setTouristType("1");
                hotelOrderTourist.setGmtCreate(now);
                hotelOrderTouristMapper.insert(hotelOrderTourist);
            }
        }

        // 星赏会积分扣除
        if (req.getUsingPoints() != null && req.getUsingPoints() > 0) {
            TransactionIntegralReq integralReq = new TransactionIntegralReq();
            integralReq.setOrderNumber(orderNumber);
            integralReq.setCtsLogin(req.getCtsLogin());
            integralReq.setPoints(new BigDecimal(req.getUsingPoints()));
            integralReq.setCtsPassword(req.getVipPwssword());
            try {
                Result starVip = starVipBusinessService.transactionIntegral(integralReq);
                if (!starVip.isSuccess()) {
                    SystemError systemError = SystemError.getDefined(starVip.getCode());
                    throw new BusinessException(systemError);
                }
            } catch (Exception e) {
                throw new BusinessException(SystemError.STAR_VIP_20006);
            }
        }

        // 下单完成后调用任务执行如果未付款则超时失效订单操作
        /* TODO 临时注释70环境放开
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("id", orderId);
        // 延迟时间,单位毫秒,1800000L=30分钟后执行
        long delayMS = 1800000L;
        OhMyClient taskClient = new OhMyClient(domain, appName, password);
        ResultDTO<Long> resultTask = taskClient.runJob(jobId, jsonObject.toJSONString(), delayMS);

        if (resultTask.isSuccess()) {
            // 任务执行成功,过期时间*2是防止任务启动时redis数据已过期
            redisTemplate.opsForValue().set(RedisConstants.ORDER_INSTANCELD_KEY + orderId, resultTask.getData(), delayMS * 2, TimeUnit.MILLISECONDS);
        }*/

        HotelOrderSubmitDTO result = EntityUtil.copy(hotelOrder, HotelOrderSubmitDTO.class);
        return result;
    }

    @Override
    public Result payment(List<HotelOrderCollectionReq> hotelOrderCollectionReqs, Long userId) {
        Long id = hotelOrderCollectionReqs.get(0).getOrderId();
        HotelOrder hotelOrder = hotelOrderMapper.selectById(id);
        if (hotelOrder == null) {
            //订单不存在
            throw new BusinessException(SystemError.HOTEL_10031);
        }
        LocalDateTime nowLocalDateTime = LocalDateTime.now();
        if (hotelOrder.getPaymentStatus().equals(OrderPaymentStatus.ALREADY_CANCEL.getCode()) || nowLocalDateTime.isAfter(hotelOrder.getPayExpireDate())) {
            // 支付超时
            throw new BusinessException(SystemError.HOTEL_10078);
        }
        UserDTO userDTO = sysUserService.queryCacheUser(userId);
        hotelOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_PAYMENT.getCode());
        hotelOrder.setModifiedId(userDTO.getId());
        hotelOrder.setGmtModified(nowLocalDateTime);
        // 计算支付总金额和支付记录
        BigDecimal amountCountHKD = BigDecimal.ZERO;//订单金额(港币)=实收金额+积分抵扣+优惠券
        BigDecimal readyMoney = BigDecimal.ZERO;//实收金额(港币)
        List<HotelOrderCollection> hotelOrderCollections = EntityUtil.copyList(hotelOrderCollectionReqs, HotelOrderCollection.class);
        for (HotelOrderCollection hotelOrderCollection : hotelOrderCollections) {
            if (hotelOrderCollection.getCurrencyId() == null) {
                //币种不能为空
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60029);
            }
            // 获取对应汇率，计算支付金额
            MainDataCurrencyQueryDTO currencyQueryDTO = getExchangeRateByName(hotelOrderCollection.getCurrencyId());
            BigDecimal marketExchangeRate = currencyQueryDTO.getMarketExchangeRate();
            BigDecimal amountHKD;
            if (hotelOrderCollection.getIsUnionpayDiscount() == 1) {
                // 使用银联优惠
                if (hotelOrder.getUsingPoints() != null || hotelOrder.getCouponId() != null) {
                    //使用了会员积分或优惠券，无法使用银联优惠
                    throw new BusinessException(SystemError.AIREXPRESS_ORDER_60025);
                }
                useAmountByBankReference(hotelOrder, hotelOrderCollection, userDTO);
                amountHKD = hotelOrderCollection.getCollectionAmount();
            } else {
                amountHKD = hotelOrderCollection.getCollectionAmount().multiply(marketExchangeRate);
                readyMoney = readyMoney.add(amountHKD);
            }
            amountCountHKD = amountCountHKD.add(amountHKD);
            String paymentNumber = generatorPaymentNumber(nowLocalDateTime);
            hotelOrderCollection.setId(SnowflakeIdWorker.nextId());
            hotelOrderCollection.setOrderId(id);
            hotelOrderCollection.setCollectionNumber(paymentNumber);
            hotelOrderCollection.setCurrency(currencyQueryDTO.getCurrencyCode());
            hotelOrderCollection.setExchangeRate(currencyQueryDTO.getMarketExchangeRate());
            hotelOrderCollection.setStandardAmount(amountHKD);//本位币金额
            hotelOrderCollection.setStatus(1);
            hotelOrderCollection.setSalerId(userDTO.getId());
            hotelOrderCollection.setSalerName(userDTO.getFullName());
            hotelOrderCollection.setIsDeleted(IsDeletedCode.NO.getCode());
            hotelOrderCollection.setCreateId(userDTO.getId());
            hotelOrderCollection.setGmtCreate(nowLocalDateTime);
            hotelOrderCollection.setModifiedId(userDTO.getId());
            hotelOrderCollection.setGmtModified(nowLocalDateTime);
        }
        // 校验应收价格
        checkAmount(amountCountHKD, hotelOrder.getReceivableAmount());

        // 添加总实收
        hotelOrder.setReceiptAmount(hotelOrder.getReceiptAmount().add(amountCountHKD));
        hotelOrder.setPayTime(nowLocalDateTime);

        /**
         * TODO API下单
         */
        HotelListDTO hotelListDTO = hotelService.queryDetail(hotelOrder.getHotelId());
        if (ProductType.API_PRODUCT.getCode().equals(hotelListDTO.getSourceType())) {
            HotelProductInfoDTO productInfoDTO = hotelProductService.selectInfo(hotelOrder.getHotelProductId());
            HotelOrderTourist orderTourist = hotelOrderTouristMapper.selectOne(Wrappers.<HotelOrderTourist>lambdaQuery()
                    .eq(HotelOrderTourist::getOrderId, hotelOrder.getId())
                    .eq(HotelOrderTourist::getIsDeleted, 0));
            if (null == productInfoDTO) {
                throw new BusinessException(SystemError.HOTEL_10014);
            }
            if (HotelApiSupplier.NCNB.name().equals(hotelListDTO.getApiSupplier())) {
                // 龙腾捷旅API产品下单
                NCNBHotelCreateOrderReq ncnbHotelCreateOrderReq = new NCNBHotelCreateOrderReq();
                ncnbHotelCreateOrderReq.setHotelId(hotelListDTO.getHotelCode());
                ncnbHotelCreateOrderReq.setRoomId(productInfoDTO.getProductCode());
                ncnbHotelCreateOrderReq.setRatePlanId("");
                ncnbHotelCreateOrderReq.setCheckIn(hotelOrder.getCheckInDate().toString());
                ncnbHotelCreateOrderReq.setCheckOut(hotelOrder.getCheckInDate().toString());
                ncnbHotelCreateOrderReq.setRoomCount(hotelOrder.getNumber());
                ncnbHotelCreateOrderReq.setCurrency(PayCurrency.HKD.getCode());
                ncnbHotelCreateOrderReq.setOrderAmount(String.valueOf(hotelOrder.getOrderAmount()));
                ncnbHotelCreateOrderReq.setBookName(hotelOrder.getContactName());
                ncnbHotelCreateOrderReq.setBookPhone(hotelOrder.getContactMobile());
                ncnbHotelCreateOrderReq.setGuestName(StrUtil.concat(true, orderTourist.getSurname(), orderTourist.getName()));
                ncnbHotelCreateOrderReq.setGuestPhone(hotelOrder.getContactMobile());
                ncnbHotelCreateOrderReq.setGuestFax("");
                // 国籍不限
                ncnbHotelCreateOrderReq.setGuestType("013002");
                ncnbHotelCreateOrderReq.setCardTypeId("");
                ncnbHotelCreateOrderReq.setCardNum("");
                ncnbHotelCreateOrderReq.setSpecialRemark(hotelOrder.getRemark());
                ncnbHotelCreateOrderReq.setReserve1("");
                ncnbHotelCreateOrderReq.setReserve2("");
                ncnbHotelCreateOrderReq.setCustomerOrderId(hotelOrder.getOrderNumber());

                Result<BookingCheckDTO> ncnbHotelOrder = ncnbHotelService.createOrder(ncnbHotelCreateOrderReq);
                if (!ncnbHotelOrder.isSuccess() || "31004".equals(ncnbHotelOrder.getData().getReturnCode())) {
                    throw new BusinessException(SystemError.HOTEL_API_10096);
                }
                hotelOrder.setApiOrderNumber(ncnbHotelOrder.getData().getOrderId());

            } else if (HotelApiSupplier.WESTMINSTER.name().equals(hotelListDTO.getApiSupplier())) {
                // TODO 西敏酒店API产品下单
            }
        }

        /**
         * API下单成功后
         * 1.减去使用的会员积分，增加消费的产生会员积分
         * 2.减去使用的优惠券(机场快线无优惠券业务)
         * 3.新增会员积分、优惠券的收款记录
         */
        useAndUpdateCrmMemberPoints(hotelOrder, readyMoney, userDTO, hotelOrderCollections);

        // 获取当前订单下的所有旅客
        List<HotelOrderTourist> hotelOrderTourists = new ArrayList<>();
        hotelOrderTourists = hotelOrderTouristMapper.selectList(Wrappers.<HotelOrderTourist>lambdaQuery()
                .eq(HotelOrderTourist::getOrderId, id)
                .eq(HotelOrderTourist::getIsDeleted, 0));
        /**
         * 生成供应商预订单
         */
        generatorSupplierBooking(hotelOrder, hotelOrderTourists, userDTO.getId(), nowLocalDateTime);

        /**
         * 生成收据
         */
        insertReceipt(hotelOrder, userId, nowLocalDateTime);

        // 保存订单,生成查询单号
        String inquiryNumber = generatorInquiryNumber();
        // 支付成功后流转【预订状态】
        Integer scheduledStatus = OrderScheduledStatus.CONFIRM_RESERVE.getCode();
        if (hotelOrder.getIsManual() == 1) {
            HotelManualOrder hotelManualOrder = hotelManualOrderMapper.selectOne(Wrappers.<HotelManualOrder>lambdaQuery().eq(HotelManualOrder::getOrderId, id));
            if (hotelManualOrder != null && hotelManualOrder.getTicketMode() == 2) {
                // 订单是外挂单并且是后台出票【预订状态】为【确认预订】
                scheduledStatus = OrderScheduledStatus.RESERVE_SUCCESS.getCode();
            }
        }
        hotelOrder.setScheduledStatus(scheduledStatus);
        hotelOrderCollectionMapper.insertBatchSomeColumn(hotelOrderCollections);
        hotelOrderMapper.updateById(hotelOrder);

        finaceCollection(hotelOrderCollections, Arrays.asList(hotelOrder.getHotelProductId()), hotelOrder.getHotelProductName(),hotelOrder.getOrderNumber(),hotelListDTO.getHotelCode());

        // 付款完成后调用取消任务执行超时失效操作
        /* TODO 临时注释70环境放开
        Long instanceId = (Long) redisTemplate.opsForValue().get(RedisConstants.ORDER_INSTANCELD_KEY + id);
        OhMyClient taskClient = new OhMyClient(domain, appName, password);
        ResultDTO<Void> resultTask = taskClient.cancelInstance(instanceId);
        if (resultTask.isSuccess()) {
            // 取消任务执行成功
            log.info("订单付款成功,取消订单失效任务操作,订单id[{}],任务实例id[{}]", id, instanceId);
        }*/

        return Result.success(id);
    }

    @Override
    public Result notPaid(Long id) {
        HotelOrder hotelOrder = hotelOrderMapper.selectById(id);
        if (hotelOrder == null || hotelOrder.getIsDeleted() == 1){
            throw new BusinessException(SystemError.HOTEL_10031);
        }
        hotelOrder.setPaymentStatus(OrderPaymentStatus.ALREADY_CANCEL.getCode());
        hotelOrder.setGmtModified(LocalDateTime.now());
        hotelOrderMapper.updateById(hotelOrder);
        return Result.success();
    }

    /**
     * 付款后生成收据
     * @param hotelOrder
     * @param userId
     * @param nowLocalDateTime
     * @return
     */
    private int insertReceipt(HotelOrder hotelOrder, Long userId, LocalDateTime nowLocalDateTime) {
        UserDTO userDTO = sysUserService.loadUserByParam(userId, 1);
        SysDepartmentDTO sysDepartmentDTO = sysDepartmentService.queryOne(userDTO.getDeptId());
        //生成收据单号
        String receiptNumber = generatorReceiptNumber(userDTO, sysDepartmentDTO, nowLocalDateTime);
        HotelOrderReceipt hotelOrderReceipt = new HotelOrderReceipt();
        hotelOrderReceipt.setId(SnowflakeIdWorker.nextId());
        hotelOrderReceipt.setOrderId(hotelOrder.getId());
        hotelOrderReceipt.setReceiptNo(receiptNumber);
        hotelOrderReceipt.setBranch(sysDepartmentDTO.getTitle());
        hotelOrderReceipt.setGuest(hotelOrder.getContactName());
        hotelOrderReceipt.setRoomNumber(String.valueOf(hotelOrder.getNumber()));
        hotelOrderReceipt.setPhone(hotelOrder.getContactMobileAreaCode() + "-" + hotelOrder.getContactMobile());
        hotelOrderReceipt.setIsDeleted(IsDeletedCode.NO.getCode());
        hotelOrderReceipt.setCreateId(userId);
        hotelOrderReceipt.setGmtCreate(nowLocalDateTime);
        hotelOrderReceipt.setModifiedId(userId);
        hotelOrderReceipt.setGmtModified(nowLocalDateTime);
        return hotelOrderReceiptMapper.insert(hotelOrderReceipt);
    }

    /**
     * 使用和更新crm会员积分
     *
     * @param hotelOrder
     * @param readyMoney                             实收金额(现金，信用卡)
     * @param user
     * @param airportExpressOrderCollectionThirdList
     */
    private void useAndUpdateCrmMemberPoints(HotelOrder hotelOrder, BigDecimal
            readyMoney, UserDTO user, List<HotelOrderCollection> airportExpressOrderCollectionThirdList) {
        // 更新CRM会员积分记录
        log.info("【机场快线订单】更新会员信息,使用积分:{}, 查询类型:{},查询号:{},证书类型:{}", hotelOrder.getUsingPoints(), hotelOrder.getMemberQueryType(), hotelOrder.getMemberQueryCode(), hotelOrder.getMemberQueryCertificatesType());
        if (hotelOrder.getUsingPoints() != null && hotelOrder.getUsingPoints() > 0) {
            // 获取人民币兑港币汇率
            MainDataCurrencyListDTO mainDataCurrencyListDTO = getExchangeRateByName(Currency.CNY.getCurrency());
            BigDecimal crmExchangeRateCNY = mainDataCurrencyListDTO.getCrmExchangeRate();
            CrmMemberQueryReq crmMemberQueryReq = new CrmMemberQueryReq(hotelOrder.getMemberQueryType(), hotelOrder.getMemberQueryCode(), hotelOrder.getMemberQueryCertificatesType().toString());
            try {
                // TODO ContactQueryDTO contactQuery = crmMemberService.queryMember(crmMemberQueryReq);
                // 构建创建用户ID，人民币金额，加分点数
                String crmUserId = String.valueOf(user.getId()).substring(0, 12);
                BigDecimal rmbAmount = readyMoney.divide(crmExchangeRateCNY, 2, BigDecimal.ROUND_HALF_UP);
                BigDecimal addPoints = readyMoney.divide(new BigDecimal(String.valueOf(CrmMemberProductPointsRateEnum.TRAFFIC_TYPE.getRate())), BigDecimal.ROUND_DOWN);
                CrmMemberUpdatePointsReq crmMemberUpdatePointsReq = new CrmMemberUpdatePointsReq();
                crmMemberUpdatePointsReq.setUpdateType(2);
                crmMemberUpdatePointsReq.setNumPoints(new BigDecimal(hotelOrder.getUsingPoints()));//do积分点数
                crmMemberUpdatePointsReq.setXCtsProdDesc("單項委託 – 酒店");//do板塊產品描述 (建議使用: 集團產品名稱 + “ – “ + 板塊產品名稱, 例如: 港澳参团游 - 主题游)")
                crmMemberUpdatePointsReq.setTxnNum(hotelOrder.getOrderNumber() + "-1");//do交易編號 (如為旅行團交易, 目前我們的格式是 旅行團交易編號 + ‘-‘ + 序號, 例如: 01P08192131025A155506-1
                crmMemberUpdatePointsReq.setAmtVal(readyMoney);
                crmMemberUpdatePointsReq.setXCtsRmbAmount(rmbAmount);
                crmMemberUpdatePointsReq.setCreateUserid(crmUserId);
                crmMemberUpdatePointsReq.setXCtsTxnOrgCode("219910000010");
                crmMemberUpdatePointsReq.setTxnChannelCd("16");
                crmMemberUpdatePointsReq.setXCtsTxnChnNum("211099000010");
                crmMemberUpdatePointsReq.setProdName("8821090000");
                crmMemberUpdatePointsReq.setXCtsProdCode("8821090300");
                // TODO crmMemberService.updatePoints(crmMemberUpdatePointsReq, contactQuery);
                // 新增-加积分记录
                if (readyMoney.compareTo(BigDecimal.ZERO) == -1) {
                    // 实收金额不能小于0
                    throw new BusinessException(SystemError.AIREXPRESS_ORDER_60020);
                }
                CrmMemberUpdatePointsReq crmMemberIncreasePointsReq = new CrmMemberUpdatePointsReq();
                crmMemberIncreasePointsReq.setUpdateType(1);
                crmMemberIncreasePointsReq.setNumPoints(addPoints);//do积分点数
                crmMemberIncreasePointsReq.setXCtsProdDesc("單項委託-火车巴士船票(机场快线)");//do板塊產品描述 (建議使用: 集團產品名稱 + “ – “ + 板塊產品名稱, 例如: 港澳参团游 - 主题游)")
                crmMemberIncreasePointsReq.setTxnNum(hotelOrder.getOrderNumber() + "-2");//do交易編號 (如為旅行團交易, 目前我們的格式是 旅行團交易編號 + ‘-‘ + 序號, 例如: 01P08192131025A155506-1
                crmMemberIncreasePointsReq.setAmtVal(readyMoney);
                crmMemberIncreasePointsReq.setXCtsRmbAmount(rmbAmount);
                crmMemberIncreasePointsReq.setCreateUserid(crmUserId);
                crmMemberIncreasePointsReq.setXCtsTxnOrgCode("219910000010");
                crmMemberIncreasePointsReq.setTxnChannelCd("16");
                crmMemberIncreasePointsReq.setXCtsTxnChnNum("211099000010");
                crmMemberIncreasePointsReq.setProdName("8821090000");
                crmMemberIncreasePointsReq.setXCtsProdCode("8821090300");
                // TODO crmMemberService.updatePoints(crmMemberIncreasePointsReq, contactQuery);
                // 新增CRM会员付款方式
                HotelOrderCollection hotelOrderCollection = new HotelOrderCollection();
                hotelOrderCollection.setId(SnowflakeIdWorker.nextId());
                hotelOrderCollection.setOrderId(hotelOrder.getId());
                hotelOrderCollection.setCollectionAmount(readyMoney);
                hotelOrderCollection.setStandardAmount(rmbAmount);
                // 支付方式：CRM星賞會積分
                hotelOrderCollection.setCollectionWayId(PayRefundMethod.CRM.getId());
                hotelOrderCollection.setCollectionWay(PayRefundMethod.CRM.getName());
                hotelOrderCollection.setIsDeleted(IsDeletedCode.NO.getCode());
                hotelOrderCollection.setCreateId(user.getId());
                hotelOrderCollection.setGmtCreate(hotelOrder.getGmtModified());
                hotelOrderCollection.setModifiedId(user.getId());
                hotelOrderCollection.setGmtModified(hotelOrder.getGmtModified());
                airportExpressOrderCollectionThirdList.add(hotelOrderCollection);
            } catch (Exception e) {
                if (e instanceof BusinessException) {
                    throw e;
                } else {
                    throw new BusinessException(SystemError.AIREXPRESS_ORDER_60009);
                }
            }
        }
        // 机场快线无优惠券业务
        /*if (hotelOrder.getCouponId() != null) {
        }*/
    }

    /**
     * 校验支付金额是否小于应收金额
     *
     * @param amountCountHKD   支付金额
     * @param receivableAmount 应收价格
     */
    private void checkAmount(BigDecimal amountCountHKD, BigDecimal receivableAmount) {
        if (amountCountHKD.compareTo(receivableAmount) < 0) {
            // 支付价格小于应收价格
            throw new BusinessException(SystemError.AIREXPRESS_ORDER_60004);
        }
    }

    private void generatorSupplierBooking(HotelOrder hotelOrder, List<HotelOrderTourist> hotelOrderTourists, Long userId, LocalDateTime localDateTime) {
        SupplierOrderSystemHotelAddReq supplierOrderSystemHotelAddReq = new SupplierOrderSystemHotelAddReq();
        log.info("【酒店订单】生成供应商预订，查询酒店产品信息, id:{}", hotelOrder.getHotelProductId());
        HotelProductInfoDTO hotelProductInfoDTO = hotelProductService.selectInfo(hotelOrder.getHotelProductId());
        log.info("【酒店订单】生成供应商预订，酒店产品信息, info:{}", JSON.toJSONString(hotelProductInfoDTO));
        // 生成供应预订单
        UserDTO chargeUser = sysUserService.queryCacheUser(hotelProductInfoDTO.getChargeId());
        // 资源所属部门ID
        supplierOrderSystemHotelAddReq.setDepartmentId(chargeUser.getDeptId());
        supplierOrderSystemHotelAddReq.setDepartment(chargeUser.getDept());
        supplierOrderSystemHotelAddReq.setBusinessType(SystemBusinessType.HOTEL.getCode());
        supplierOrderSystemHotelAddReq.setReserveTypeId(SupplierReserveTypeEnum.HOTEL.getId());
        supplierOrderSystemHotelAddReq.setSaleType(SalesMethod.SINGLE_SALE.getCode());
        if (hotelOrder.getIsManual() == 1) {
            supplierOrderSystemHotelAddReq.setProductType(ProductType.PLUG.getCode());
        } else {
            supplierOrderSystemHotelAddReq.setProductType(hotelProductInfoDTO.getSourceType());
        }
        supplierOrderSystemHotelAddReq.setTotalFee(hotelOrder.getOrderAmount());
        supplierOrderSystemHotelAddReq.setPayableAmount(hotelOrder.getReceivableAmount());
        supplierOrderSystemHotelAddReq.setSaleNumber(hotelOrder.getOrderNumber());
        supplierOrderSystemHotelAddReq.setProductNumber(hotelProductInfoDTO.getProductCode());
        supplierOrderSystemHotelAddReq.setProductName(hotelProductInfoDTO.getName());
        supplierOrderSystemHotelAddReq.setCurrencyId(hotelOrder.getCostCurrencyId());
        supplierOrderSystemHotelAddReq.setCurrency(hotelOrder.getCostCurrencyName());
        // 供应商ID
        supplierOrderSystemHotelAddReq.setSupplierId(hotelProductInfoDTO.getSupplierId());
        // 供应商订单类型
        supplierOrderSystemHotelAddReq.setSupplierOrderType("1");
        // 供应商订单号(第三方单号)
        supplierOrderSystemHotelAddReq.setSupplierOrderNumber("");
        // 确认状态
        supplierOrderSystemHotelAddReq.setConfirmStatus(SupplierConfirmStatus.CONFIRMED.getCode());
        supplierOrderSystemHotelAddReq.setConfirmTime(localDateTime);

        // 构建供应商预订-酒店入住信息
        SupplierSystemOrderHotelCheckInAddReq supplierSystemOrderHotelCheckInAddReq = new SupplierSystemOrderHotelCheckInAddReq();
        supplierSystemOrderHotelCheckInAddReq.setHotelId(hotelProductInfoDTO.getHotelId());
        supplierSystemOrderHotelCheckInAddReq.setHotelName(hotelOrder.getHotelName());
        supplierSystemOrderHotelCheckInAddReq.setProductId(hotelProductInfoDTO.getId());
        supplierSystemOrderHotelCheckInAddReq.setProductName(hotelProductInfoDTO.getName());
        supplierSystemOrderHotelCheckInAddReq.setIncludeBreakfast(hotelProductInfoDTO.getHasBreakfast());
        supplierSystemOrderHotelCheckInAddReq.setCheckInTime(DateUtil.toLocalDateTime(hotelOrder.getCheckInDate()));
        supplierSystemOrderHotelCheckInAddReq.setCheckOutTime(DateUtil.toLocalDateTime(hotelOrder.getCheckOutDate()));
        supplierSystemOrderHotelCheckInAddReq.setNum(hotelOrder.getNumber());
        supplierSystemOrderHotelCheckInAddReq.setNightNum(hotelOrder.getNights());
        // 房间单价-无需计算服务费和加幅
        supplierSystemOrderHotelCheckInAddReq.setPrice(hotelOrder.getReceivableAmount());
        supplierSystemOrderHotelCheckInAddReq.setRoomTypeId(hotelProductInfoDTO.getRoomId());
        supplierSystemOrderHotelCheckInAddReq.setRoomType(hotelOrder.getRoomName());
        // 小计-无需计算服务费和加幅
        supplierSystemOrderHotelCheckInAddReq.setTotalPrice(hotelOrder.getReceivableAmount());
        supplierSystemOrderHotelCheckInAddReq.setExtraService("");
        supplierSystemOrderHotelCheckInAddReq.setSuitablePeople(hotelProductInfoDTO.getTargetPopulation());
        supplierSystemOrderHotelCheckInAddReq.setCustomerRemark(hotelOrder.getRemark());
        supplierSystemOrderHotelCheckInAddReq.setSupplierRemark(hotelOrder.getRemark());

        // 构建供应商预订-酒店入住游客
        List<SupplierSystemOrderHotelTouristAddReq> supplierSystemOrderAirExpressDetailAddReqList = new ArrayList<>();
        Optional.ofNullable(hotelOrderTourists).orElse(new ArrayList<>()).forEach(hotelOrderTourist -> {
            SupplierSystemOrderHotelTouristAddReq supplierSystemOrderHotelTouristAddReq = new SupplierSystemOrderHotelTouristAddReq();
            supplierSystemOrderHotelTouristAddReq.setTouristId(hotelOrderTourist.getId());
            supplierSystemOrderHotelTouristAddReq.setTouristName(hotelOrderTourist.getTouristName());
            supplierSystemOrderHotelTouristAddReq.setTouristTypeId(Long.valueOf(hotelOrderTourist.getTouristType()));
            supplierSystemOrderHotelTouristAddReq.setTouristType(TouristType.parseValue(Integer.valueOf(hotelOrderTourist.getTouristType())));
            supplierSystemOrderHotelTouristAddReq.setContactMobile(hotelOrder.getContactMobile());
            supplierSystemOrderHotelTouristAddReq.setContactAreaCode(hotelOrder.getContactMobileAreaCode());

            supplierSystemOrderAirExpressDetailAddReqList.add(supplierSystemOrderHotelTouristAddReq);
        });
        supplierSystemOrderHotelCheckInAddReq.setSupplierSystemOrderHotelTouristAddReqList(supplierSystemOrderAirExpressDetailAddReqList);


        List<SupplierSystemOrderHotelCheckInAddReq> supplierSystemOrderHotelCheckInAddReqs = new ArrayList<>();
        supplierSystemOrderHotelCheckInAddReqs.add(supplierSystemOrderHotelCheckInAddReq);
        supplierOrderSystemHotelAddReq.setSupplierSystemOrderHotelCheckInAddReqList(supplierSystemOrderHotelCheckInAddReqs);
        supplierOrderService.addSystemHotel(supplierOrderSystemHotelAddReq, userId);
    }

    /**
     * 获取银联优惠金额
     *
     * @param hotelOrder
     * @param collection
     * @param user
     * @return
     */
    private void useAmountByBankReference(HotelOrder hotelOrder, HotelOrderCollection
            collection, UserDTO user) {
        OperateBankConformQueryReq operateBankConformQueryReq = new OperateBankConformQueryReq();
        operateBankConformQueryReq.setId(collection.getUnionpayDiscountId());//银联优惠ID
        operateBankConformQueryReq.setCardNumber(collection.getPayer());//卡号
        operateBankConformQueryReq.setTotalPaidIn(hotelOrder.getOrderAmount());//订单金额
        operateBankConformQueryReq.setBusinessType(SystemBusinessType.HOTEL.getCode());
        operateBankConformQueryReq.setRelationId(hotelOrder.getHotelProductId());//订单ID
        operateBankConformQueryReq.setChannelId(OrderSource.CPM.getCode().longValue());//订单来源
        operateBankConformQueryReq.setUserId(user.getId());
//        operateBankConformQueryReq.setDiscountObjectId();//会员类型
        Result<OperateBankPreferenceQueryDTO> operateBankPreferenceQueryDTOResult = operateBankPreferenceService.queryConform(operateBankConformQueryReq);
        if (!operateBankPreferenceQueryDTOResult.isSuccess()) {
            // 校验银行优惠不满足条件
            SystemError defined = SystemError.getDefined(operateBankPreferenceQueryDTOResult.getCode());
            throw new BusinessException(defined);
        }
        OperateBankPreferenceQueryDTO bankQueryDto = operateBankPreferenceQueryDTOResult.getData();
        if (bankQueryDto.getDiscountType() == 1) {
            // 使用满额折扣优惠
            // 校验应收价格是否符合满减优惠
            if (hotelOrder.getReceivableAmount().compareTo(bankQueryDto.getFullAmount()) == -1) {
                // 校验银行优惠不满足条件
                throw new BusinessException(SystemError.AIREXPRESS_ORDER_60018);
            }
            collection.setCollectionAmount(bankQueryDto.getReductionAmount());
        } else {
            // 使用百分比优惠
            BigDecimal currentAmount = hotelOrder.getReceivableAmount().multiply(new BigDecimal(String.valueOf(bankQueryDto.getDiscountPercent())));
            currentAmount = currentAmount.compareTo(bankQueryDto.getMaxDiscount()) > 0 ? bankQueryDto.getMaxDiscount() : currentAmount;
            collection.setCollectionAmount(currentAmount);
        }
        /**
         * 扣减银联优惠
         */
        OperateBankDeductReq deductReq = new OperateBankDeductReq();
        deductReq.setId(collection.getUnionpayDiscountId());//银联优惠ID
        deductReq.setCardNumber(collection.getPayer());//卡号
        deductReq.setTotalPaidIn(hotelOrder.getOrderAmount());//订单金额
        deductReq.setBusinessType(SystemBusinessType.AIR_EXPRESS.getCode());
        deductReq.setRelationId(hotelOrder.getHotelProductId());//订单ID
        deductReq.setChannelId(OrderSource.CPM.getCode().longValue());//订单来源
        TokenUser tokenUser = new TokenUser();
        tokenUser.setId(user.getId());
        Result deductResult = operateBankPreferenceService.deduct(deductReq, tokenUser);
        if (!deductResult.isSuccess()) {
            // 校验银行优惠不满足条件
            SystemError defined = SystemError.getDefined(deductResult.getCode());
            throw new BusinessException(defined);
        }
    }

    /**
     * 收款新增财务中心认款
     * @param hotelOrderCollections
     * @param productIds
     * @param productName
     * @param orderNumber
     * @param hotelCode
     * @return
     */
    private void finaceCollection(List<HotelOrderCollection> hotelOrderCollections, List<Long> productIds, String productName, String orderNumber,String hotelCode) {
        List<BillAddCollectionReq> req = new ArrayList<>();
        hotelOrderCollections.forEach(hotelOrderCollection -> {
            BillAddCollectionReq billAddCollectionReq = new BillAddCollectionReq();
            billAddCollectionReq.setBillNumber(hotelOrderCollection.getCollectionNumber());
            billAddCollectionReq.setBusinessType(SystemBusinessType.HOTEL.getCode());
            billAddCollectionReq.setCollectionWayId(hotelOrderCollection.getCollectionWayId());
            billAddCollectionReq.setCollectionWayName(hotelOrderCollection.getCollectionWay());
            billAddCollectionReq.setCollectionAmount(hotelOrderCollection.getCollectionAmount());
            billAddCollectionReq.setCurrencyId(hotelOrderCollection.getCurrencyId());
            billAddCollectionReq.setCurrencyName(hotelOrderCollection.getCurrency());
            billAddCollectionReq.setExchangeRate(hotelOrderCollection.getExchangeRate().doubleValue());
            billAddCollectionReq.setCollectionTime(hotelOrderCollection.getGmtCreate());
            billAddCollectionReq.setProductId(productIds);
            billAddCollectionReq.setProductName(productName);
            billAddCollectionReq.setSaleUserId(hotelOrderCollection.getSalerId());
            billAddCollectionReq.setSaleUserName(hotelOrderCollection.getSalerName());
            billAddCollectionReq.setSaleDeptId(sysUserService.queryCacheUser(hotelOrderCollection.getSalerId()).getDeptId());
            billAddCollectionReq.setUserId(hotelOrderCollection.getCreateId());
            //默认全款
            billAddCollectionReq.setCollectionTypeId(1365184144700788737L);
            billAddCollectionReq.setCollectionTypeName("全款");
            billAddCollectionReq.setSaleOrderNumber(orderNumber);
            billAddCollectionReq.setProductNumber(hotelCode);
            req.add(billAddCollectionReq);
        });
        log.info("发起收款新增财务中心认款开始");
        Result result = financeBillService.addCollection(req);
        if (!result.isSuccess()) {
            SystemError systemError = SystemError.getDefined(result.getCode());
            throw new BusinessException(systemError);
        }
        log.info("发起收款新增财务中心认款成功");
    }
}
